// Copyright 2007-2008 Helsinki Institute for Information Technology
// and the authors.
//
// Authors: Harri Hämäläinen <hhamalai@iki.fi>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//////////////////////////
// FeedConnector
// Browser side HttpInterface for Fusion
// Requires:    httpconnector.js    (AJAX requests
//              util.js             (utility methods
//
//  methods:
//      fetchData(force_reload)
//          Fetch all blog data. If force_reload is true, fetches already
//          fetched data again
//      getComments(entry_path)
//          Get comments for post specified by entry_path
//      getCommentCount(entry_path)
//          Get number of comments for post specified by entry_path
//      getRealName()
//          Get blog owner's name
//      getFeedTitle()
//          Get the title of blog
//      getEntries()
//          Get entries in this blog as Array
//      getEntry(entry_id)
//      getEntryPath(index)
//      getMyTags(entry_path)
//      getNickname()
//      getTags(entry_id)
//          Get tags for specified entry
//      getPopularTags(entry_id, limit)
//          Get most popular tags as arrayfor specified entry,
//          limit is maximum number of tags returned.
//      postComment(entry_id, nick, tags, msg)
//          XXX Refactor me to handle posting comment and tags in different
//          methods.
//      postEntry(postObject)
//      removeDuplicates(array)
//      removePost(entry_id)
//          XXX Real delete now available. Refactor me to use it.


function FeedConnector() {
    var entries = null;
    var comments = null;
    var tags = null;
    var info = null;

    this.fetchData = function(force_reload) {
        if (entries == null || force_reload) {
            entries = HttpConnector.doGet('/content/feed/entries/?output=json');
            entries = entries.evalJSON(true);
        }
        if (comments == null || force_reload) {
            comments = HttpConnector.doGet('/content/feed/comments/?output=json');
            comments = comments.evalJSON(true);
        }
        if (tags == null || force_reload) {
            tags = HttpConnector.doGet('/content/feed/tags/?output=json');
            tags = tags.evalJSON(true);
        }
    }

    this.getComments = function(entry_path) {
        this.fetchData()
        var result = new Array();
        for (var i = 0; i < comments.data.length; i += 1) {
            if (comments.data[i][0].indexOf(entry_path) >= 0) {
                try {
                    result.push(comments.data[i][1].evalJSON(true));
                } catch (e) {
                }
            }
        }
        return result;
    }

    this.getCommentCount = function(entry_path) {
        this.fetchData();
        var count = 0;
        for (var i = 0; i < comments.data.length; i += 1) {
            if (comments.data[i][0].indexOf(entry_path) >= 0) {
                count += 1;
            }
        }
        return count;
    }

    this.getRealName = function(){
        var data = HttpConnector.doGet('/content/info/?output=json');
        var obj = data.evalJSON(true);
        var defaultProfile = obj['default_profile'];
        return HttpConnector.doGet('http://'+defaultProfile+'.hexlabel.net/content/info/title.txt');
    }

    this.getFeedTitle = function() {
        return HttpConnector.doGet('/content/info/title.txt') || "Untitled Blog";
    }

    this.getEntries = function() {
        this.fetchData();
        var keys = entries.data;
        keys.sort(FeedConnector.compareEntryDates);
        var result = new Array();
        for (var i = 0; i < keys.length; i += 1) {
            if (keys[i][0].match(/.+/)) {
                result.push(keys[i]);
            }
        }
        return result;
    }

    this.getEntry = function(entry_id) {
        var entry = HttpConnector.doGet('/content/feed/entries/' + entry_id + '/entry.json');
        return entry.evalJSON(true);
    }

    this.getEntryPath = function(index) {
        this.fetchData();
        var entries_data = entries.data;
        return (entries_data[index][0].match(/(\w*\/\w*)/))[1];
    }

    this.getMyTags = function(entry_path) {
        var tags_data = tags.data;
        var info = HttpConnector.doGet('/content/info/?output=json');
        info = info.evalJSON(true);
        var defaultProfile = info['default_profile'];
        var fingerprint = HttpConnector.doGet('http://'+defaultProfile+'.hexlabel.net/?output=sha1-hex');
        for (var i=0; i<tags_data.length; i++) {
            if (tags_data[i][0] == entry_path+'/0x'+fingerprint) {
                return tags_data[i][1].evalJSON().join(", ");
            }
        }
    }
    
    this.getNickname = function() {
        var nick = comment_nickname.value;
        if (nick == '') {
            nick = this.getRealName();
        }
        return nick;
    }

    this.removeEmptyIndices = function(tag_array) {
        var ret = new Array();
        for (var i=0; i<tag_array.length; i += 1) {
            if (tag_array[i] != '') {
                ret.push(tag_array[i]);
            }
        }
        return ret;
    }

    this.removeDuplicates = function(tag_array) {
        var ret = new Array();
        var obj = new Object;
        for (var i=0; i<tag_array.length; i += 1) {
            obj[tag_array[i]] = 1;
        }
        ret = new Array();
        for(var key in obj) {
            ret.push(key);
        }
        return ret;
    }

    this.getTags = function(entry_id) {   
        this.fetchData();
        var entry_tags = new Array();
        for (var i = 0; i < tags.data.length; i += 1) {
            if (tags.data[i][0].indexOf(entry_id) >= 0) {
                try {
                    var tag_array = tags.data[i][1].evalJSON(true);
                    tag_array = this.removeEmptyIndices(tag_array);
                    tag_array = this.removeDuplicates(tag_array);
                    if (tag_array.length > 0)
                        entry_tags = entry_tags.concat(tag_array);
                }
                catch (e) {
                    alert(e);
                }
            }
        }
        return entry_tags;
    }

    this.getPopularTags = function(entry_id, limit) {
        if (!limit) limit = 5;
        var tag_array = this.getTags(entry_id);
        var assoc = new Object;
        var uniqtags = 0;
        for (var i=0; i<tag_array.length; i+= 1) {
            if (tag_array[i].length > 30) { // Tag too long
                continue;
            }
            if (assoc[tag_array[i]] == null) {
                assoc[tag_array[i]] = 1;
                uniqtags += 1;
            }
            else {
                assoc[tag_array[i]] += 1;
            }
        }
        var ret = new Array();
        for (var i=0; i<limit && i<uniqtags; i+= 1) {
            var greatest = null;
            for (var key in assoc) {
                if ((assoc[key] > assoc[greatest])||(greatest == null))
                    greatest = key;
            }
            if (greatest != null) {
                ret.push(greatest);
                delete assoc[greatest];
            }
        }
        return ret;
    }

    this.postComment = function(entry_id, nick, tags, msg) {
        var profile = getDefaultProfile();
        if(!profile) return;
        var comment = Object.toJSON({
            published: getISODate(),
            author: {
                profile: profile,
                name: nick
            },
            content: msg
        });
        
        tags = tags.replace(/\W+/g, ","); // Convert all white space & special characters to commas..
        tags = Object.toJSON(tags.split(','));
        
        try {
            if (msg != '') {
                var url =  '/content/feed/comments/' + entry_id + '/' + getISODate() + '/!/comment.json';
                HttpConnector.doPost(url, comment);
            }
            var url =  '/content/feed/tags/' + entry_id + '/!/tags.json';
            HttpConnector.doPost(url, tags);
            this.fetchData(true);
        } catch (e) {
            alert(e);
        }
    }

    this.postEntry = function(postObject) {
        var profile = getDefaultProfile();
        if(!profile) {
            return false;
        }
        if(!postObject['id']) {
            postObject['id'] = 'http://hiit.fi/P2P-Fusion/Blog/'+randomHex(30);
            postObject['published'] = update_date;
        }
        
        if(!postObject['published']) {
            postObject['published'] = getISODate();
        }
        var update_date = getISODate();
        var entry = {
            id: postObject['id'],
            published: postObject['published'],
            updated: update_date,
            title: postObject['title'],
            author: {
                name: postObject['author'],
                profile: {
                    xmlns: 'http://hiit.fi/P2P-Fusion',
                    $t: profile
                }
            },
            content: postObject['content']
        };

        if (postObject['enclosure_type'] == 'add_new') {
            enclosure_filename = postObject['enclosure_file'].split(/[\/]/);
            enclosure_filename = enclosure_filename[enclosure_filename.length-1];
            entry['link'] = [{
                rel: 'enclosure',
                href: '/file/' + enclosure_filename
            }];
        } else if (postObject['enclosure_type'] == 'add_existing') {
            entry['link'] = [{
                rel: 'enclosure',
                href: postObject['enclosure_file']
            }];
        }
        
        entry = Object.toJSON(entry);

        if (!postObject['entry_key']) {
            // OBSOLETE: Generate random hex string with 20 characters (+ leading '0x')
            // OBSOLETE: postObject['entry_key'] = randomHex(20);
            // Entries will be identified by ISO timestamp and authors fingerprint. 
            // In case of shared blog, the fingerprint might be absent.
            postObject['entry_key'] = getISODate() + '/!';
        }
 

        var url = '/content/feed/entries/' + postObject['entry_key'] + '/entry.json';

        HttpConnector.doPost(url, entry);

        this.fetchData(true);
        
        return true;
    }

    this.removePost = function(entry_path) {
        var entry_key = entry_path.split('/', 2).join('/');
        var url = '/content/feed/entries/'+entry_key+'/entry.json';
        FeedConnector.removeEnclosure(entry_key)
        HttpConnector.doDelete(url, '');
    }

    FeedConnector.removeEnclosure = function(entry_key) {
        var url = '/content/feed/entries/'+entry_key+'/entry.json?output=json';
        var entry = HttpConnector.doGet(url).evalJSON(true);
        for (var i=0; i<entry.link.length; i++) {
        	if (entry.link[i].rel == 'enclosure') {
        		HttpConnector.doDelete('/content/'+entry.link[i].href);
        	}
        }
        delete entry.link;
        HttpConnector.doPut('/content/feed/entries/'+entry_key+'/entry.json', Object.toJSON(entry));
    }

    FeedConnector.compareEntryDates = function(entry1, entry2)
    {
        a = entry1[1].evalJSON(true);
        b = entry2[1].evalJSON(true);
        if (a.published < b.published)
            return -1;
        if (a.published > b.published)
            return 1;
        return 0;
    }
}




function GenericView() {
    var feed_connector = new FeedConnector();

    // This is called when EntryEditor's submit button is clicked
    GenericView.checkEditorFields = function() {
		// Not implemented
        return false;
    }

    this.postComment = function(entry_id, nick,tags,msg) {
        //feed_connector.postComment(entry_id, nick, tags, msg);
    }
    this.postEntry = function(title, author, content, entry_key, enclosure_type, enclosure_filename) {
        //feed_connector.postEntry(title, author, content, entry_key, enclosure_type, enclosure_filename);
    }
    this.updateTags = function(entry_id) {
        //return escape(feed_connector.getPopularTags(entry_id));
    }
    this.getFeedTitle = function() {
        return '<div id="feed_header" align="center"><a href="'
                +'/presentation/web/index.html'
                +'">'+feed_connector.getFeedTitle()+'</a></div>';
    }

    this.getAuthor = function(obj) {
        try {
            return obj.author.name.escapeHTML();
        } catch(e) {
            return "";
        }
    }

    this.getContent = function(obj) {
        try {
            return obj.content.escapeHTML();
        } catch (e) {
            return "";
        }
    }
    this.getThumbnail = function(obj) {
    	try {
    		return obj.thumbnail.url.escapeHTML();
    	} catch (e) {
    		return "";
    	}
    }
    this.getEnclosure = function(obj) {
        try {
            return obj.enclosure.href.escapeHTML();
        } catch (e) {
            return "";
        }
    }
    this.getEntryID = function(obj) {
        try {
            return obj.id.escapeHTML();
        } catch (e) {
            return "";
        }
    }
    this.getPublishDate = function(obj) {
        try {
            return obj.published.escapeHTML();
        } catch (e) {
            return "";
        } 
    }
    this.getFancyPublishDate = function(obj) {
        try {
        	var date = new Date();
        	date.setMilliseconds(obj.published);
            return date;
        } catch (e) {
            return "";
        } 
    }
    
    this.getTitle = function(obj) {
        try {
            return obj.title.escapeHTML();
        } catch(e) {
            return "";
        }
    }

    this.getEnclosureBar = function(enclosure_values,open) {
        var enclosureTemplate;
        if(open)
        {
        enclosureTemplate = new Template(
            '<div id="enclosure#{enclosure_number}"><table class="bar"><tr><td id="expand#{enclosure_number}" /><img src="/static/icons/down.png" alt="v" /></td><td class="filename"><a id="enclosure_link#{enclosure_number}" href="#{enclosure_url}">#{enclosure_name}</a></td></tr></table>'
            +'<div id="content#{enclosure_number}" class="entry_enclosures"><object data="#{enclosure_url}">Your browser lacks support for this kind of media files.</object></div></div>'
        );
        }
        else
        {
        enclosureTemplate = new Template(
            '<div id="enclosure#{enclosure_number}"><table class="bar"><tr><td><img id="expand#{enclosure_number}" src="/static/icons/right.png" alt=">" /></td><td class="filename"><a id="enclosure_link#{enclosure_number}" href="#{enclosure_url}">#{enclosure_name}</a></td></tr></table></div>'
        );
        }
        return enclosureTemplate.evaluate(enclosure_values);
    }

    this.getEntries = function() {
        var entries = feed_connector.getEntries();
        var entryTemplate = new Template(
            '<hr />'
            +'<div class="entry">'
            +'<div class="entry_title"><a href="?entry=#{entry_id}">#{title}</a></div>'
            +'<div class="entry_author">#{published} #{author}</div>'
            +'<div id="entry_tags">#{tags}</div>'
            +'<div class="entry_content">#{content}</div>'
            +'#{enclosure}'
            +'<div class="entry_comments"><a href="?entry=#{entry_id}">#{comment_count} comments</a></div>'
            +'</div>'
        );

        var inner = "";
        var entry;
        var e = 0;
        for (var i = entries.length-1; i >= 0; i -= 1) {
        	var entry_id = entries[i][0].split('/');
        	if (entry_id.length == 0)
        		continue;
        	else {
        		entry_id = entry_id[0];
        	}
        	
            try {
                entry = entries[i][1].evalJSON(true);
                if (entry == '()')
                    continue;
            } catch (e) {
                continue;
            }
            var entry_values = {
                entry_id: entry_id, 
                title: this.getTitle(entry),
                published: getUTCFriendlyDate(this.getPublishDate(entry_id)),
                author: this.getAuthor(entry),
                tags: escape(feed_connector.getPopularTags(entry_id)),
                content: this.getContent(entry),
                comment_count: feed_connector.getCommentCount(entry_id)
            };
            if  (this.getEnclosure(entry) != '') {
                var enclosure_values = {
                    enclosure_url: '/'+this.getEnclosure(entry),
                    enclosure_name: this.getEnclosure(entry).split('/').pop(),
                    enclosure_number: e++
                };
                entry_values['enclosure'] = this.getEnclosureBar(enclosure_values, false);
                /*
                entry_values['enclosure'] = this.getenclosure(enclosure_values, true);
                */
            }
            inner += entryTemplate.evaluate(entry_values);
        }

        return inner;
    }
    
    this.getEntry = function(entry_id) {
        var entry = feed_connector.getEntry(entry_id);
        var entry_template = new Template(
            '<div class="entry">'
            +'<div class="entry_title">#{title}</div>'
            +'<div class="entry_author">#{published} #{author}</div>'
            +'<div id="entry_tags">#{tags}</div>'
            +'<div class="entry_content">#{content}</div>'
            +'<div class="entry_enclosures"><a href="#{enclosure_url}">#{enclosure}</a></div>'
            +'</div>'
        );
        var date = new Date();
        date.setMilliseconds(entry_id);
        
        var entry_values = {
            title: this.getTitle(entry),
            published: date,
            author: this.getAuthor(entry),
            tags: escape(feed_connector.getPopularTags(entry_id)),
            content: this.getContent(entry)
        };
        if  (this.getEnclosure(entry) != '') {
                entry_values['enclosure'] = '<img src="/'+this.getThumbnail(entry)+'" /><br />Enclosure',
                entry_values['enclosure_url'] = '/content'+this.getEnclosure(entry)
        }
        return entry_template.evaluate(entry_values);
    }

    this.getComments = function(entry_id) {
        var inner = '<div id="entry_comments"><hr /><h3>Comments</h3>';
        var comments = feed_connector.getComments(entry_id);
        var comments_template = new Template(
            '<div class="comment_header">#{published} #{author} wrote:</div>'
            +'<blockquote class="comment_content">#{content}</blockquote>'
        )
        for (var i = 0; i<comments.length; i += 1) {
            var comment_values = {
                author: this.getAuthor(comments[i]),
                content: this.getContent(comments[i])
            }
            inner += comments_template.evaluate(comment_values);
        }
        inner += '</div>';
        return inner;
    }

    this.getCommentForm = function(entry_path) {
    	// Not implemented
    	return '';
    }

    this.getEditorForm = function(entry_key) {
    	// Not implemented
    	return '';
    }

    this.getOptions = function(entry_path) {
    	// Not implemented
    	return '';
    }

    this.askAndRemove = function(entry_path) {
    	// Not implemented
    }
}




var FeedView = {

    init: function(element) {
        getenclosure2 = function(enclosure_values,open) {
            var enclosureTemplate;
            if(open)
            {
            enclosureTemplate = new Template(
                '<table class="bar"><tr><td class="filename"><a id="enclosure_link#{enclosure_number}" href="#{enclosure_url}">#{enclosure_name}</a></td></tr></table>'
                +'<div id="content#{enclosure_number}" class="entry_enclosures"><object data="#{enclosure_url}">Your browser lacks support for this kind of media files.</object></div>'
            );
            }
            else
            {ihan
            enclosureTemplate = new Template(
                '<table class="bar"><tr><td></td><td class="filename"><a id="enclosure_link#{enclosure_number}" href="#{enclosure_url}">#{enclosure_name}</a></td></tr></table>'
            );
            }
            return enclosureTemplate.evaluate(enclosure_values);
        }
        this.expander = function(e) {
            expand = function() {
                var enclosure_values = {
                    enclosure_url: $('enclosure_link' + e).getAttribute('href'),
                    enclosure_name: $('enclosure_link' + e).textContent,
                    enclosure_number: e
                };
                if( $('content' + e))
                {
                    html = getenclosure2(enclosure_values,false);
                    //alert('kiinni (' + $('content' + e) + ')');
                }
                else
                {
                    html = getenclosure2(enclosure_values,true);
                    //alert('auki');
                }

                $('enclosure' + e).innerHTML = html
                //alert($('enclosure' + e).innerHTML);
                //$('expand' + e).onclick = expand;

            }
            return expand;
        }

        var generic_view = new GenericView();
        element.innerHTML = generic_view.getFeedTitle();
        element.innerHTML += generic_view.getEntries();
        element.innerHTML += generic_view.getOptions();
        var e = 0;

        while ($('expand' + e))
        {
            $('expand' + e).onclick = this.expander(e);
            e++;
        }
    }
}




var EntryView = {
    init: function(element, entry_path) {
        var self = this;
        var generic_view = new GenericView();
        element.innerHTML = generic_view.getFeedTitle();
        element.innerHTML += generic_view.getEntry(entry_path);
        element.innerHTML += generic_view.getCommentForm(entry_path);
        element.innerHTML += generic_view.getComments(entry_path);
        element.innerHTML += generic_view.getOptions(entry_path);
        
        this.onMessageEntered = function(){
        }
    }
}



function get_params() {
    var result = {};
    var q = location.search;
    if (q.length > 1) {
        q = q.substring(1, q.length);
        var fields = q.split('&');
        for (var i = 0; i < fields.length; i += 1) {
            var parts = fields[i].split('=');
            var key = parts[0];
            var value = parts[1];
            result[key] = decodeURIComponent(value);
        }
    }
    return result;
}





load = function() {
    //     $("documenthead").innerHTML += "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"Atom\" href=\"/feed/"+collection+"\" />";
    var q = get_params();
    var main_element = $('center');

    if (q.entry) {
        entry_key =  location.href.match(/web\/index.html\?entry=(.+)/)[1];
        new EntryView.init(main_element, entry_key);
    } else if (q.new_post) {
        new EntryEditor.init(main_element);
    } else {
        new FeedView.init(main_element);
    }
}
